package cn.battlecruiser.vishnu.auth.config;

import java.security.KeyPair;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.AccessTokenConverter;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;

import cn.battlecruiser.vishnu.auth.constant.SecurityConstants;
import cn.battlecruiser.vishnu.auth.token.converter.JwtAccessToken;
import cn.battlecruiser.vishnu.auth.userdetails.UserDetailsImpl;

@Configuration
@EnableAuthorizationServer
@Order(6)
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

	@Value("${jwt.certificate.store.file}")
	private Resource keystore;

	@Value("${jwt.certificate.store.password}")
	private String keystorePassword;

	@Value("${jwt.certificate.key.alias}")
	private String keyAlias;

	@Value("${jwt.certificate.key.password}")
	private String keyPassword;
	@Autowired
	private AuthenticationManager authenticationManager;

	@Autowired
	private DataSource dataSource;
	@Autowired
	private UserDetailsService userDetailsService;

	// @Autowired
	// private RedisConnectionFactory redisConnectionFactory;
	//
	// @Bean
	// RedisTokenStore redisTokenStore(){
	// return new RedisTokenStore(redisConnectionFactory);
	// }

	// token存储数据库
	@Bean
	public JdbcTokenStore jdbcTokenStore() {
		return new JdbcTokenStore(dataSource);
	}

	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		clients.inMemory()
        .withClient("clientId").secret("password")
        .redirectUris("http://localhost:9999/login").authorizedGrantTypes("authorization_code", "refresh_token")
        .scopes("myscope").autoApprove(true).accessTokenValiditySeconds(3000).refreshTokenValiditySeconds(1800);

//		clients.withClientDetails(clientDetails());
	}

	@Bean
	public ClientDetailsService clientDetails() {
		return new JdbcClientDetailsService(dataSource);
	}

	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
		// endpoints
		// .tokenStore(redisTokenStore())
		// .userDetailsService(userDetailsService)
		// .authenticationManager(authenticationManager)
		// // 配置JwtAccessToken转换器
		// .accessTokenConverter(jwtAccessTokenConverter());

		// endpoints.tokenServices(defaultTokenServices());

		// token增强配置
		TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
		tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), jwtAccessTokenConverter()));
//
//		endpoints.tokenStore(jdbcTokenStore()).tokenEnhancer(tokenEnhancerChain)
//				.authenticationManager(authenticationManager).reuseRefreshTokens(false)
//				.userDetailsService(userDetailsService);
		
		endpoints.tokenStore(jdbcTokenStore()).tokenEnhancer(tokenEnhancerChain).authenticationManager(authenticationManager).accessTokenConverter(jwtAccessTokenConverter()).userDetailsService(userDetailsService);
	}

	/**
	 * 使用非对称加密算法来对Token进行签名
	 * 
	 * @return
	 */
	@Bean
	public JwtAccessTokenConverter jwtAccessTokenConverter() {
		KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(keystore, keystorePassword.toCharArray());
		KeyPair keyPair = keyStoreKeyFactory.getKeyPair(keyAlias, keyPassword.toCharArray());
		JwtAccessTokenConverter converter = new JwtAccessToken();
		converter.setKeyPair(keyPair);
		return converter;
	}

	/**
	 * jwt 生成token 定制化处理
	 *
	 * @return TokenEnhancer
	 */
	@Bean
	public TokenEnhancer tokenEnhancer() {
		return (accessToken, authentication) -> {
			final Map<String, Object> additionalInfo = new HashMap<>(2);
			additionalInfo.put("license", SecurityConstants.LICENSE);
			UserDetailsImpl user = (UserDetailsImpl) authentication.getUserAuthentication().getPrincipal();
			if (user != null) {
				additionalInfo.put("userId", user.getUsername());
			}
			((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
			return accessToken;
		};
	}

	/**
	 * <p>
	 * 注意，自定义TokenServices的时候，需要设置@Primary，否则报错，
	 * </p>
	 * 
	 * @return
	 */
//	@Primary
//	@Bean
//	public DefaultTokenServices defaultTokenServices() {
//		DefaultTokenServices tokenServices = new DefaultTokenServices();
//		tokenServices.setTokenStore(jdbcTokenStore());
//		tokenServices.setSupportRefreshToken(true);
//		tokenServices.setClientDetailsService(clientDetails());
//		tokenServices.setAccessTokenValiditySeconds(60 * 60 * 12); // token有效期自定义设置，默认12小时
//		tokenServices.setRefreshTokenValiditySeconds(60 * 60 * 24 * 7);// 默认30天，这里修改
//		return tokenServices;
//	}

//	@Override
//	public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
//		security.tokenKeyAccess("permitAll()");
//		security.checkTokenAccess("isAuthenticated()");
//		security.allowFormAuthenticationForClients();
//	}

}
